如何在發佈 ASP.NET Core 網站時自動套用 Shadow Copying 設定
TLDR
- Shadow Copying 可解決 ASP.NET Core 運行時 DLL 被鎖定導致無法更新的問題。
- 透過在專案根目錄預置
web.config,發佈時會自動合併設定,無需手動修改伺服器檔案,適合 CI/CD 流程。 - Shadow Copying 的設定參數會隨 Hosting Bundle 版本變動:7.0+ 使用
enableShadowCopy,6.0 使用experimentalEnableShadowCopy。 - Shadow Copying 機制並非版本管理工具,其設計為「僅保留當前版本」,每次啟動會嘗試刪除目錄下其他舊資料夾。
- 升級 .NET 版本後務必手動清理 Shadow Copying 目錄,否則會觸發 500.30 錯誤。
- 應避免在應用程式目錄中寫入檔案或 Log,以免頻繁觸發 Shadow Copying 導致應用程式重啟。
解決 DLL 鎖定與自動化部署問題
什麼情況下會遇到這個問題:當 ASP.NET Core 應用程式在 IIS 上運行時,相關 DLL 檔案會被鎖定,導致無法直接覆蓋更新,必須先停止應用程式集區。
傳統做法是手動修改伺服器上的 web.config,但這不符合自動化部署原則,且容易因人工疏失導致設定遺失。更好的做法是在 Web 專案根目錄預先建立一個包含 Shadow Copying 設定的 web.config。發佈時,MSBuild 會自動將此檔案作為基礎進行合併,確保部署後的設定正確無誤。
若要同時設定環境變數(如 ASPNETCORE_ENVIRONMENT),可在 .pubxml 中定義 <EnvironmentName>,發佈後的 web.config 將會自動合併環境變數與 Shadow Copying 設定:
xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="dotnet" arguments=".\WebApi.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess">
<handlerSettings>
<handlerSetting name="enableShadowCopy" value="true" />
<handlerSetting name="shadowCopyDirectory" value="../ShadowCopy/" />
</handlerSettings>
<environmentVariables>
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Staging" />
</environmentVariables>
</aspNetCore>
</system.webServer>
</location>
</configuration>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
透過此方式,CI/CD 流程僅需執行標準指令即可:
bash
dotnet publish -c Release -p:EnvironmentName=Staging1
版本差異注意事項
設定參數名稱取決於伺服器安裝的 Hosting Bundle 版本,而非專案本身的 .NET 版本:
- Hosting Bundle 7.0.0 以上:使用
enableShadowCopy。 - Hosting Bundle 6.0.0:使用
experimentalEnableShadowCopy。
關於 Shadow Copying 的資料夾管理機制
什麼情況下會遇到這個問題:開發者誤以為 shadowCopyDirectory 會自動維護多個版本供回滾使用,或擔心該資料夾會無限膨脹。
根據 AspNetCoreModuleV2 的原始碼分析,Shadow Copying 的設計初衷並非版本管理。當系統選定一個新的流水號資料夾作為執行路徑後,會立即啟動執行緒刪除該目錄下所有其他的資料夾。若發現目錄內有多個資料夾並存,通常是清理執行緒尚未執行完畢,或是舊檔案因鎖定而刪除失敗,而非系統有意保留。
WARNING
- 升級 .NET 版本後,必須手動刪除 Shadow Copying 資料夾,否則 IIS 會出現 500.30 錯誤,事件檢視器會顯示
directory_iterator找不到路徑的異常。 - 使用 Shadow Copying 時,應避免在應用程式目錄中寫入檔案或 Log,否則每次檔案異動都可能觸發 Shadow Copying 機制,導致應用程式不必要的重啟。
異動歷程
- 2025-03-18 初版文件建立。
- 2025-04-08 補充升級 .NET 版本造成 Shadow Copying 異常。
- 2025-06-27 補充使用 Shadow Copying 時需避免在應用程式目錄寫入檔案的注意事項。
- 2026-01-22 補充 Shadow Copying 資料夾管理機制的常見誤解與源碼說明。
